﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Forms;

namespace RhythmGame
{
    internal class Scoring
    {
        private static uint score = 0;
        private static int combo = 0;

        // 准确度相关变量
        private static double accuracy = 0;
        private static int totalNotes = 0;          // 总音符数
        private static int totalBreaks = 0;         // 总 Break 物块数
        private static int judgedNotes = 0;         // 已判定的音符数
        private static int criticalPerfectCount = 0;
        private static int perfectCount = 0;
        private static int greatCount = 0;
        private static int goodCount = 0;
        private static int missCount = 0;

        private static bool hasBreakNotes = false;

        private static int criticalPerfect = 500;
        private static int perfect = 300;
        private static int great = 100;
        private static int good = 50;
        private static int miss = 0;

        private static readonly Scoring singleInstance = new Scoring();

        // 私有构造函数
        private Scoring() { }        

        public static Scoring Instance
        {
            get
            {
                if (singleInstance == null)
                {
                    throw new ArgumentNullException("Scoring instance is null.");
                }
                return singleInstance;
            }
        }

        // 积分
        public static uint Score
        {
            get { return score; }
            set { score = value; }
        }

        // 连击数
        public static int Combo
        {
            get { return combo; }
            set { combo = value; }
        }

        // 准确度
        public static double Accuracy
        {
            get { return accuracy; }
            set { accuracy = value; }
        }

        // 总音符数
        public static int TotalNotes
        {
            get { return totalNotes; }
            set { totalNotes = value; }
        }

        // 总 Break 物块数
        public static int TotalBreaks
        {
            get { return totalBreaks; }
            set { totalBreaks = value; }
        }

        // 已判定的音符数
        public static int JudgedNotes
        {
            get { return judgedNotes; }
            set { judgedNotes = value; }
        }

        // Critical Perfect 计数
        public static int CriticalPerfectCount
        {
            get { return criticalPerfectCount; }
            set { criticalPerfectCount = value; }
        }

        // Perfect 计数
        public static int PerfectCount
        {
            get { return perfectCount; }
            set { perfectCount = value; }
        }

        // Great 计数
        public static int GreatCount
        {
            get { return greatCount; }
            set { greatCount = value; }
        }

        // Good 计数
        public static int GoodCount
        {
            get { return goodCount; }
            set { goodCount = value; }
        }

        // Miss 计数
        public static int MissCount
        {
            get { return missCount; }
            set { missCount = value; }
        }

        public static int CriticalPerfect
        {
            get { return criticalPerfect; }
            set { criticalPerfect = value; }
        }
        public static int Perfect
        {
            get { return perfect; }
            set { perfect = value; }
        }
        public static int Great
        {
            get { return great; }
            set { great = value; }
        }
        public static int Good
        {
            get { return good; }
            set { good = value; }
        }
        public static int Miss
        {
            get { return miss; }
            set { miss = value; }
        }

        // 初始化总音符数和是否存在 Break 物块
        public static void InitializeAccuracy(BeatMap map)
        {
            totalNotes = map.GetTotalNotes();
            totalBreaks = map.GetTotalBreaks();
            hasBreakNotes = map.HasBreakNotes();
            // 根据计分方式初始化准确度
            switch (Settings.Instance.ScoringMethod)
            {
                case 1:
                    accuracy = 100.0;
                    break;
                case 2:
                    accuracy = 0.0;
                    break;
                case 3:
                    accuracy = hasBreakNotes ? 101.0 : 100.0;
                    break;
            }
            judgedNotes = 0;
            criticalPerfectCount = 0;
            perfectCount = 0;
            greatCount = 0;
            goodCount = 0;
            missCount = 0;
        }

        // 设置判定
        internal static void ApplyJudgement(Game game, string text, bool isBreak)
        {
            game.SetLabelDecideText(text);
            switch (text)
            {
                case "CRITICAL PERFECT":
                    game.SetLabelDecideColor(Settings.Instance.JudgeTextColor[0]);
                    break;
                case "PERFECT":
                    game.SetLabelDecideColor(Settings.Instance.JudgeTextColor[1]);
                    break;
                case "GREAT":
                    game.SetLabelDecideColor(Settings.Instance.JudgeTextColor[2]);
                    break;
                case "GOOD":
                    game.SetLabelDecideColor(Settings.Instance.JudgeTextColor[3]);
                    break;
                case "MISS":
                    game.SetLabelDecideColor(Settings.Instance.JudgeTextColor[4]);
                    break;
            }
            CalculateCombo(game, text);
            CalculateAccuracy(game, text, isBreak);
            CalculateScore(game, text, isBreak);
        }

        // 计算连击数
        internal static void CalculateCombo(Game game, string decideText)
        {
            switch (decideText)
            {
                case "CRITICAL PERFECT":
                case "PERFECT":
                case "GREAT":
                case "GOOD":
                    combo++;
                    break;
                case "MISS":
                    combo = 0;
                    break;
                default:
                    combo = 0;
                    break;
            }
            game.SetLabelComboText(combo.ToString());
        }

        // 计算积分
        internal static void CalculateScore(Game game, string decideText, bool isBreak)
        {
            switch (decideText)
            {
                case "CRITICAL PERFECT":
                    if (isBreak)
                    {
                        score += (uint)criticalPerfect;
                    }
                    else
                    {
                        score += (uint)perfect;
                    }
                    break;
                case "PERFECT":
                    score += (uint)perfect;
                    break;
                case "GREAT":
                    score += (uint)great;
                    break;
                case "GOOD":
                    score += (uint)good;
                    break;
                case "MISS":
                    score += (uint)miss;
                    break;
            }
            game.SetLabelScoreText(score.ToString("D10"));
        }

        // 计算准确度
        internal static void CalculateAccuracy(Game game, string decideText, bool isBreak)
        {
            judgedNotes++;

            // 更新判定计数
            switch (decideText)
            {
                case "CRITICAL PERFECT":
                    criticalPerfectCount++;
                    break;
                case "PERFECT":
                    perfectCount++;
                    break;
                case "GREAT":
                    greatCount++;
                    break;
                case "GOOD":
                    goodCount++;
                    break;
                case "MISS":
                    missCount++;
                    break;
            }

            // 根据计分方式计算准确度
            switch (Settings.Instance.ScoringMethod)
            {
                case 1:
                    if (isBreak)
                    {
                        if (decideText == "CRITICAL PERFECT")
                        {
                            if (totalBreaks > 0)
                            {
                                // Accuracy 增加，最高增加总量不超过 1%
                                double increment = 0.01 / totalBreaks * 100;
                                accuracy += Math.Min(increment, 1.0);
                            }
                        }
                        else if (decideText == "GREAT" || decideText == "GOOD" || decideText == "MISS")
                        {
                            // Accuracy 减少
                            double decrement = GetDecrement(decideText);
                            accuracy -= decrement;
                        }
                        // Perfect 不变
                    }
                    else
                    {
                        if (decideText == "GREAT" || decideText == "GOOD" || decideText == "MISS")
                        {
                            // Accuracy 减少
                            double decrement = GetDecrement(decideText);
                            accuracy -= decrement;
                        }
                        // Perfect 或 Critical Perfect 不变
                    }
                    break;

                case 2:
                    if (decideText != "MISS")
                    {
                        // Accuracy 增加
                        double increment = GetIncrement(decideText);
                        accuracy += increment;
                    }
                    // Miss 不增加
                    break;

                case 3:
                    if (!hasBreakNotes)
                    {
                        // 若谱面中无 Break 物块，使用方式 1
                        goto case 1;
                    }
                    if (isBreak)
                    {
                        if (decideText != "CRITICAL PERFECT")
                        {
                            // Accuracy 减少
                            double decrement = GetDecrement(decideText);
                            if (decideText == "PERFECT")
                            {
                                decrement += 0.01 / totalBreaks * 100;
                            }
                            accuracy -= decrement;
                        }
                        // Critical Perfect，不变
                    }
                    else
                    {
                        if (decideText == "GREAT" || decideText == "GOOD" || decideText == "MISS")
                        {
                            // Accuracy 减少
                            double decrement = GetDecrement(decideText);
                            accuracy -= decrement;
                        }
                        // Perfect，不变
                    }
                    break;
            }

            // 确保 Accuracy 在 0% - 最大值之间
            double maxAccuracy = hasBreakNotes ? 101.0 : 100.0;
            if (accuracy < 0.0)
            {
                accuracy = 0.0;
            }
            else if (accuracy > maxAccuracy)
            {
                accuracy = maxAccuracy;
            }

            game.SetLabelAccuracyText(accuracy.ToString("F4") + "%");
        }

        // 根据判定结果获取准确度的增加值（用于方式 2）
        private static double GetIncrement(string decideText)
        {
            switch (decideText)
            {
                case "CRITICAL PERFECT":
                    double increment;
                    if (totalNotes - totalBreaks <= 0)
                    {
                        increment = 1.01 / totalNotes * 100;
                    }
                    else if (totalBreaks == 0)
                    {
                        increment = 1.0 / totalNotes * 100;
                    }
                    else
                    {
                        increment = 1.0 / (totalNotes - totalBreaks) * 100 + 0.01 / totalBreaks * 100;
                    }
                    return increment;
                case "PERFECT":
                    return 1.0 / totalNotes * 100;
                case "GREAT":
                    return 0.75 / totalNotes * 100;
                case "GOOD":
                    return 0.5 / totalNotes * 100;
                default:
                    return 0.0;
            }
        }

        // 根据判定结果获取准确度的减少值（用于方式 1 和 3）
        private static double GetDecrement(string decideText)
        {
            switch (decideText)
            {
                case "GREAT":
                    return 0.25 / totalNotes * 100;
                case "GOOD":
                    return 0.5 / totalNotes * 100;
                case "MISS":
                    return 1.0 / totalNotes * 100;
                default:
                    return 0.0;
            }
        }

        // 重置计分数据（在开始新的游戏时调用）
        public static void Reset(Game game)
        {
            score = 0;
            combo = 0;
            accuracy = 0;
            totalNotes = 0;
            judgedNotes = 0;
            criticalPerfectCount = 0;
            perfectCount = 0;
            greatCount = 0;
            goodCount = 0;
            missCount = 0;
            hasBreakNotes = false;
            game.SetLabelScoreText(score.ToString("D10"));
            game.SetLabelComboText(combo.ToString());
            game.SetLabelDecideText("  ");
        }
    }
}
